package com.cloudree.gllib.shape;

import android.opengl.GLES20;
import android.opengl.Matrix;

import com.cloudree.gllib.BaseApp;
import com.cloudree.gllib.R;
import com.cloudree.gllib.constants.RenderData;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;

/**
 * Created by Administrator on 2017/8/8.
 */
public class VBOCube extends Shape {
    private FloatBuffer vertexBuffer;
    private FloatBuffer colorBuffer;
    private FloatBuffer normalBuffer;
    private FloatBuffer textureBuffer;

    private int mTexture;
    private int[] buffers;

    @Override
    public void loadingMaterial() {
        vertexBuffer = ByteBuffer.allocateDirect(RenderData.VBO.vertexData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(RenderData.VBO.vertexData);
        vertexBuffer.position(0);
        colorBuffer = ByteBuffer.allocateDirect(RenderData.VBO.colorData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(RenderData.VBO.colorData);
        colorBuffer.position(0);
        normalBuffer = ByteBuffer.allocateDirect(RenderData.VBO.normalData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(RenderData.VBO.normalData);
        normalBuffer.position(0);
        textureBuffer = ByteBuffer.allocateDirect(RenderData.VBO.textureData.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(RenderData.VBO.textureData);
        textureBuffer.position(0);
    }

    @Override
    public void compileShader() {
        int vertexShader = generateShader(GLES20.GL_VERTEX_SHADER, getVertexShaderCode());
        int fragmentShader = generateShader(GLES20.GL_FRAGMENT_SHADER, getFragmentShaderCode());
        String[] attrs = new String[]{"aPosition", "aColor", "aNormal", "aTexCoordinate"};
        mProgram = generateGlProgram(vertexShader, fragmentShader, attrs);

        mTexture = loadTexture(BaseApp.getApp(), R.mipmap.ic_launcher);

        //vbo
        buffers = new int[4];
        GLES20.glGenBuffers(4, buffers, 0);//buffers[0] vertex buffers[1] color buffers[2] normal buffers[3] texture
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vertexBuffer.capacity() * 4, vertexBuffer, GLES20.GL_STATIC_DRAW);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, colorBuffer.capacity() * 4, colorBuffer, GLES20.GL_STATIC_DRAW);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[2]);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, normalBuffer.capacity() * 4, normalBuffer, GLES20.GL_STATIC_DRAW);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[3]);
        GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, textureBuffer.capacity() * 4, textureBuffer, GLES20.GL_STATIC_DRAW);

        //release buffer
        vertexBuffer.limit(0);
        vertexBuffer = null;
        colorBuffer.limit(0);
        colorBuffer = null;
        normalBuffer.limit(0);
        normalBuffer = null;
        textureBuffer.limit(0);
        textureBuffer = null;

    }

    @Override
    public void draw(float[] mvpMatrix, float[] modelMatrix, float[] viewMatrix, float[] projectionMatrix) {

    }

    public void draw(float[] mvpMatrix, float[] modelMatrix, float[] viewMatrix, float[] projectionMatrix, float[] lightEyeSpace) {
        //draw cube
        GLES20.glUseProgram(mProgram);
        //bind attribute
        int mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
        int mMVMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVMatrix");
        int mLightPositionHandle = GLES20.glGetUniformLocation(mProgram, "uLightPosition");
        int mTextureUnitHandle = GLES20.glGetUniformLocation(mProgram, "uTextureUnit");

        int mPositionHandle = GLES20.glGetAttribLocation(mProgram, "aPosition");
        int mColorHandle = GLES20.glGetAttribLocation(mProgram, "aColor");
        int mNormalHandle = GLES20.glGetAttribLocation(mProgram, "aNormal");
        int mTexturePositionHandle = GLES20.glGetAttribLocation(mProgram, "aTexture");

        //allocate drawing order
        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[0]);
        GLES20.glEnableVertexAttribArray(mPositionHandle);
        GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, 0);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[1]);
        GLES20.glEnableVertexAttribArray(mColorHandle);
        GLES20.glVertexAttribPointer(mColorHandle, 4, GLES20.GL_FLOAT, false, 0, 0);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[2]);
        GLES20.glEnableVertexAttribArray(mNormalHandle);
        GLES20.glVertexAttribPointer(mNormalHandle, 3, GLES20.GL_FLOAT, false, 0, 0);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, buffers[3]);
        GLES20.glEnableVertexAttribArray(mTexturePositionHandle);
        GLES20.glVertexAttribPointer(mTexturePositionHandle, 2, GLES20.GL_FLOAT, false, 0, 0);

        GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);

        // Set the active texture unit to texture unit 0.
        GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
        // Bind the texture to this unit.
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexture);
        // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
        GLES20.glUniform1i(mTextureUnitHandle, 0);

        //combine matrix
        // (which currently contains model * view).
        Matrix.multiplyMM(mvpMatrix, 0, viewMatrix, 0, modelMatrix, 0);

        // Pass in the modelview matrix.
        GLES20.glUniformMatrix4fv(mMVMatrixHandle, 1, false, mvpMatrix, 0);

        // This multiplies the modelview matrix by the projection matrix, and stores the result in the MVP matrix
        // (which now contains model * view * projection).
        Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, mvpMatrix, 0);

        // Pass in the combined matrix.
        GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

        // Pass in the light position in eye space.
        GLES20.glUniform3f(mLightPositionHandle, lightEyeSpace[0], lightEyeSpace[1], lightEyeSpace[2]);


        GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 36);
    }

    @Override
    public String getVertexShaderCode() {
        return readRawFile(BaseApp.getApp(), R.raw.texture_vertex_shader);
    }

    @Override
    public String getFragmentShaderCode() {
        return readRawFile(BaseApp.getApp(), R.raw.texture_fragment_shader);
    }
}
